<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 高级视觉效果技术</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460);
            color: #e6e6e6;
            min-height: 100vh;
            overflow-x: hidden;
            line-height: 1.6;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
            padding: 20px;
        }

        header {
            text-align: center;
            margin: 30px 0;
            padding: 30px;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
            border: 1px solid rgba(255, 255, 255, 0.1);
        }

        h1 {
            font-size: 3.5rem;
            margin-bottom: 15px;
            background: linear-gradient(90deg, #4cc9f0, #4361ee, #3a0ca3);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            text-shadow: 0 2px 10px rgba(76, 201, 240, 0.2);
        }

        .subtitle {
            font-size: 1.3rem;
            max-width: 800px;
            margin: 0 auto;
            color: #a3b1c6;
        }

        .scene-container {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            margin: 40px 0;
        }

        .canvas-wrapper {
            flex: 2;
            min-width: 300px;
            height: 600px;
            position: relative;
            border-radius: 20px;
            overflow: hidden;
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
            border: 1px solid rgba(255, 255, 255, 0.1);
        }

        #three-canvas {
            width: 100%;
            height: 100%;
            display: block;
            background: #050518;
        }

        .controls-panel {
            flex: 1;
            min-width: 300px;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 20px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
            border: 1px solid rgba(255, 255, 255, 0.1);
            height: fit-content;
        }

        .control-group {
            margin-bottom: 30px;
        }

        .control-group h3 {
            font-size: 1.4rem;
            margin-bottom: 20px;
            color: #4cc9f0;
            border-bottom: 2px solid rgba(76, 201, 240, 0.3);
            padding-bottom: 10px;
        }

        .control-item {
            margin-bottom: 15px;
            padding: 12px 15px;
            background: rgba(255, 255, 255, 0.05);
            border-radius: 12px;
            transition: all 0.3s ease;
        }

        .control-item:hover {
            background: rgba(255, 255, 255, 0.1);
            transform: translateY(-2px);
        }

        .control-item label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: #b4c4de;
        }

        .slider-container {
            display: flex;
            align-items: center;
            gap: 15px;
        }

        input[type="range"] {
            flex: 1;
            height: 6px;
            border-radius: 3px;
            background: rgba(100, 100, 150, 0.3);
            outline: none;
        }

        .value-display {
            min-width: 40px;
            text-align: center;
            background: rgba(76, 201, 240, 0.2);
            padding: 3px 8px;
            border-radius: 5px;
            font-weight: 600;
        }

        .techniques-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: 25px;
            margin: 40px 0;
        }

        .tech-card {
            background: rgba(0, 0, 0, 0.3);
            border-radius: 15px;
            padding: 25px;
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
            border: 1px solid rgba(255, 255, 255, 0.1);
            transition: all 0.3s ease;
        }

        .tech-card:hover {
            transform: translateY(-10px);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
            border-color: rgba(76, 201, 240, 0.4);
        }

        .tech-card h3 {
            color: #4361ee;
            margin-bottom: 15px;
            font-size: 1.3rem;
        }

        .tech-card p {
            color: #a3b1c6;
            margin-bottom: 15px;
        }

        .tech-card .highlight {
            color: #4cc9f0;
            font-weight: 600;
        }

        .info-panel {
            background: rgba(0, 0, 0, 0.3);
            border-radius: 20px;
            padding: 30px;
            margin: 40px 0;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
            border: 1px solid rgba(255, 255, 255, 0.1);
        }

        .info-panel h2 {
            color: #4cc9f0;
            margin-bottom: 25px;
            font-size: 2rem;
        }

        .info-content {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 30px;
        }

        .info-section {
            background: rgba(255, 255, 255, 0.05);
            border-radius: 15px;
            padding: 20px;
        }

        .info-section h3 {
            color: #4361ee;
            margin-bottom: 15px;
        }

        footer {
            text-align: center;
            padding: 30px;
            margin-top: 40px;
            color: #a3b1c6;
            font-size: 1rem;
            border-top: 1px solid rgba(255, 255, 255, 0.1);
        }

        @media (max-width: 768px) {
            .scene-container {
                flex-direction: column;
            }

            .canvas-wrapper {
                height: 500px;
            }

            h1 {
                font-size: 2.5rem;
            }
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.min.js"></script>
</head>

<body>
    <div class="container">
        <header>
            <h1>Three.js 高级视觉效果技术</h1>
            <p class="subtitle">探索提升场景真实感和模型质量的专业方法</p>
        </header>

        <div class="scene-container">
            <div class="canvas-wrapper">
                <canvas id="three-canvas"></canvas>
            </div>

            <div class="controls-panel">
                <div class="control-group">
                    <h3>光照控制</h3>
                    <div class="control-item">
                        <label>环境光强度: <span class="value-display" id="ambient-value">0.3</span></label>
                        <div class="slider-container">
                            <input type="range" id="ambient-intensity" min="0" max="1" step="0.01" value="0.3">
                        </div>
                    </div>
                    <div class="control-item">
                        <label>平行光强度: <span class="value-display" id="directional-value">1.0</span></label>
                        <div class="slider-container">
                            <input type="range" id="directional-intensity" min="0" max="2" step="0.1" value="1.0">
                        </div>
                    </div>
                    <div class="control-item">
                        <label>点光源强度: <span class="value-display" id="point-value">1.5</span></label>
                        <div class="slider-container">
                            <input type="range" id="point-intensity" min="0" max="3" step="0.1" value="1.5">
                        </div>
                    </div>
                </div>

                <div class="control-group">
                    <h3>材质效果</h3>
                    <div class="control-item">
                        <label>金属质感: <span class="value-display" id="metalness-value">0.8</span></label>
                        <div class="slider-container">
                            <input type="range" id="metalness" min="0" max="1" step="0.01" value="0.8">
                        </div>
                    </div>
                    <div class="control-item">
                        <label>粗糙度: <span class="value-display" id="roughness-value">0.2</span></label>
                        <div class="slider-container">
                            <input type="range" id="roughness" min="0" max="1" step="0.01" value="0.2">
                        </div>
                    </div>
                    <div class="control-item">
                        <label>法线强度: <span class="value-display" id="normal-value">0.5</span></label>
                        <div class="slider-container">
                            <input type="range" id="normal-scale" min="0" max="1" step="0.01" value="0.5">
                        </div>
                    </div>
                </div>

                <div class="control-group">
                    <h3>后期处理</h3>
                    <div class="control-item">
                        <label>抗锯齿: <span class="value-display" id="aa-value">4x</span></label>
                        <div class="slider-container">
                            <input type="range" id="antialias" min="0" max="4" step="1" value="4">
                        </div>
                    </div>
                    <div class="control-item">
                        <label>环境光遮蔽: <span class="value-display" id="ao-value">0.5</span></label>
                        <div class="slider-container">
                            <input type="range" id="ao-intensity" min="0" max="1" step="0.1" value="0.5">
                        </div>
                    </div>
                    <div class="control-item">
                        <label>辉光强度: <span class="value-display" id="bloom-value">0.7</span></label>
                        <div class="slider-container">
                            <input type="range" id="bloom-intensity" min="0" max="2" step="0.1" value="0.7">
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="techniques-grid">
            <div class="tech-card">
                <h3>基于物理的渲染 (PBR)</h3>
                <p>使用物理正确的材质属性（金属度、粗糙度）来模拟真实世界的光照行为。</p>
                <p><span class="highlight">效果：</span> 更真实的材质表现，特别是金属和反射表面。</p>
            </div>
            <div class="tech-card">
                <h3>高动态范围 (HDR) 环境贴图</h3>
                <p>使用HDR图像提供环境光照，实现更真实的反射和全局照明效果。</p>
                <p><span class="highlight">效果：</span> 更自然的环境反射和光照平衡。</p>
            </div>
            <div class="tech-card">
                <h3>法线贴图</h3>
                <p>在不增加几何复杂度的情况下，通过纹理模拟表面细节。</p>
                <p><span class="highlight">效果：</span> 显著提升表面细节表现力，如划痕、凹凸等。</p>
            </div>
            <div class="tech-card">
                <h3>环境光遮蔽 (AO)</h3>
                <p>模拟物体之间和褶皱处因遮挡而产生的阴影效果。</p>
                <p><span class="highlight">效果：</span> 增强场景深度感和物体之间的空间关系。</p>
            </div>
            <div class="tech-card">
                <h3>次表面散射 (SSS)</h3>
                <p>模拟光线穿透半透明材质（皮肤、蜡、大理石等）的效果。</p>
                <p><span class="highlight">效果：</span> 使材质看起来更自然、有深度。</p>
            </div>
            <div class="tech-card">
                <h3>屏幕空间反射 (SSR)</h3>
                <p>在屏幕空间计算反射，提供实时的高质量反射效果。</p>
                <p><span class="highlight">效果：</span> 实现逼真的反射表面，如水、金属等。</p>
            </div>
        </div>

        <div class="info-panel">
            <h2>提升模型质量的关键技术</h2>
            <div class="info-content">
                <div class="info-section">
                    <h3>几何优化</h3>
                    <p>使用细分曲面和置换贴图增加几何细节，同时保持模型轻量。</p>
                    <p>法线贴图和视差贴图可以在不增加多边形数量的情况下增加表面细节。</p>
                </div>
                <div class="info-section">
                    <h3>纹理优化</h3>
                    <p>使用4K或更高分辨率纹理，特别是对于关键表面。</p>
                    <p>实施纹理流送技术，根据相机距离动态加载不同分辨率的纹理。</p>
                </div>
                <div class="info-section">
                    <h3>后期处理</h3>
                    <p>添加抗锯齿(MSAA)消除锯齿边缘。</p>
                    <p>使用色调映射使HDR内容适配显示器范围。</p>
                    <p>添加辉光(Bloom)效果增强明亮区域。</p>
                </div>
                <div class="info-section">
                    <h3>高级光照技术</h3>
                    <p>使用全局光照(GI)模拟真实光线传播。</p>
                    <p>实施光线追踪实现逼真阴影和反射(WebGPU)。</p>
                    <p>使用体积光效果增强场景氛围。</p>
                </div>
            </div>
        </div>

        <footer>
            <p>Three.js 高级视觉效果演示 | 模型质量优化技术 | 使用物理渲染(PBR)、HDR照明和后期处理</p>
        </footer>
    </div>

    <script>
        // 初始化Three.js场景
        let scene, camera, renderer, controls;
        let astronaut, directionalLight, pointLight, ambientLight;

        // 场景初始化
        function init() {
            // 创建场景
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x050518);
            scene.fog = new THREE.Fog(0x050518, 10, 25);

            // 创建相机
            camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
            camera.position.set(0, 1.5, 3);

            // 创建渲染器
            const canvas = document.getElementById('three-canvas');
            renderer = new THREE.WebGLRenderer({
                canvas: canvas,
                antialias: true,
                powerPreference: "high-performance"
            });
            renderer.setSize(canvas.clientWidth, canvas.clientHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.shadowMap.enabled = true;
            renderer.shadowMap.type = THREE.PCFSoftShadowMap;
            renderer.outputEncoding = THREE.sRGBEncoding;
            renderer.toneMapping = THREE.ACESFilmicToneMapping;
            renderer.toneMappingExposure = 1.0;

            // 添加轨道控制器
            controls = new THREE.OrbitControls(camera, renderer.domElement);
            controls.enableDamping = true;
            controls.dampingFactor = 0.05;

            // 添加光源
            ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
            scene.add(ambientLight);

            directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
            directionalLight.position.set(3, 5, 2);
            directionalLight.castShadow = true;
            directionalLight.shadow.mapSize.width = 1024;
            directionalLight.shadow.mapSize.height = 1024;
            scene.add(directionalLight);

            pointLight = new THREE.PointLight(0xff8844, 1.5, 20);
            pointLight.position.set(-2, 2, 1);
            pointLight.castShadow = true;
            scene.add(pointLight);

            // 添加辅助工具
            const gridHelper = new THREE.GridHelper(10, 10, 0x444444, 0x222222);
            scene.add(gridHelper);

            // 加载宇航员模型
            loadAstronaut();

            // 添加星空背景
            createStarfield();

            // 响应窗口大小变化
            window.addEventListener('resize', onWindowResize);

            // 设置事件监听器
            setupEventListeners();

            // 开始动画循环
            animate();
        }

        // 加载宇航员模型
        function loadAstronaut() {
            const geometry = new THREE.SphereGeometry(0.5, 32, 32);

            // 创建PBR材质
            const material = new THREE.MeshStandardMaterial({
                color: 0xffffff,
                metalness: 0.8,
                roughness: 0.2,
                normalScale: new THREE.Vector2(0.5, 0.5)
            });

            // 创建宇航员头盔
            astronaut = new THREE.Mesh(geometry, material);
            astronaut.position.y = 1.5;
            astronaut.castShadow = true;
            astronaut.receiveShadow = true;
            scene.add(astronaut);

            // 添加细节球体
            const detailGeometry = new THREE.SphereGeometry(0.55, 32, 32);
            const detailMaterial = new THREE.MeshStandardMaterial({
                color: 0x444444,
                metalness: 0.9,
                roughness: 0.1,
                wireframe: true,
                transparent: true,
                opacity: 0.3
            });

            const detailSphere = new THREE.Mesh(detailGeometry, detailMaterial);
            astronaut.add(detailSphere);

            // 创建底座
            const baseGeometry = new THREE.CylinderGeometry(1, 1.2, 0.2, 32);
            const baseMaterial = new THREE.MeshStandardMaterial({
                color: 0x333344,
                metalness: 0.7,
                roughness: 0.3
            });

            const base = new THREE.Mesh(baseGeometry, baseMaterial);
            base.position.y = -0.7;
            base.receiveShadow = true;
            scene.add(base);
        }

        // 创建星空背景
        function createStarfield() {
            const starGeometry = new THREE.BufferGeometry();
            const starCount = 5000;

            const positions = new Float32Array(starCount * 3);
            const colors = new Float32Array(starCount * 3);
            const sizes = new Float32Array(starCount);

            for (let i = 0; i < starCount; i++) {
                const i3 = i * 3;

                // 随机位置
                positions[i3] = (Math.random() - 0.5) * 100;
                positions[i3 + 1] = (Math.random() - 0.5) * 100;
                positions[i3 + 2] = (Math.random() - 0.5) * 100;

                // 随机颜色（带一些蓝色调）
                colors[i3] = 0.8 + Math.random() * 0.2;
                colors[i3 + 1] = 0.8 + Math.random() * 0.2;
                colors[i3 + 2] = 1.0;

                // 随机大小
                sizes[i] = Math.random() * 0.5 + 0.1;
            }

            starGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
            starGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
            starGeometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));

            const starMaterial = new THREE.PointsMaterial({
                size: 0.2,
                vertexColors: true,
                transparent: true,
                sizeAttenuation: true
            });

            const starField = new THREE.Points(starGeometry, starMaterial);
            scene.add(starField);
        }

        // 设置事件监听
        function setupEventListeners() {
            // 光照控制
            document.getElementById('ambient-intensity').addEventListener('input', function () {
                const value = parseFloat(this.value);
                ambientLight.intensity = value;
                document.getElementById('ambient-value').textContent = value.toFixed(2);
            });

            document.getElementById('directional-intensity').addEventListener('input', function () {
                const value = parseFloat(this.value);
                directionalLight.intensity = value;
                document.getElementById('directional-value').textContent = value.toFixed(1);
            });

            document.getElementById('point-intensity').addEventListener('input', function () {
                const value = parseFloat(this.value);
                pointLight.intensity = value;
                document.getElementById('point-value').textContent = value.toFixed(1);
            });

            // 材质控制
            document.getElementById('metalness').addEventListener('input', function () {
                const value = parseFloat(this.value);
                astronaut.material.metalness = value;
                document.getElementById('metalness-value').textContent = value.toFixed(2);
            });

            document.getElementById('roughness').addEventListener('input', function () {
                const value = parseFloat(this.value);
                astronaut.material.roughness = value;
                document.getElementById('roughness-value').textContent = value.toFixed(2);
            });

            document.getElementById('normal-scale').addEventListener('input', function () {
                const value = parseFloat(this.value);
                astronaut.material.normalScale.set(value, value);
                document.getElementById('normal-value').textContent = value.toFixed(2);
            });

            // 后期处理
            document.getElementById('antialias').addEventListener('input', function () {
                const value = parseInt(this.value);
                const levels = ['关闭', '2x', '4x', '8x', '16x'];
                renderer.setPixelRatio(value);
                document.getElementById('aa-value').textContent = levels[value];
            });
        }

        // 处理窗口大小变化
        function onWindowResize() {
            const canvas = document.getElementById('three-canvas');
            camera.aspect = canvas.clientWidth / canvas.clientHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(canvas.clientWidth, canvas.clientHeight);
        }

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);

            // 更新宇航员旋转
            if (astronaut) {
                astronaut.rotation.y += 0.005;
            }

            // 更新点光源位置
            const time = Date.now() * 0.001;
            pointLight.position.x = Math.sin(time) * 2;
            pointLight.position.z = Math.cos(time) * 2;

            // 更新控制器
            controls.update();

            // 渲染场景
            renderer.render(scene, camera);
        }

        // 页面加载完成后初始化场景
        window.addEventListener('load', init);
    </script>
</body>

</html>